/**
 * Copyright 2008 Mathias Doenitz, http://lis.to/
 *
 * This file is part of the lis.to java desktop client. The lis.to java desktop client is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * The lis.to java desktop client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with the lis.to java desktop client.
 * If not, see http://www.gnu.org/licenses/
 */

package listo.client.dragdrop;

import com.google.inject.Inject;
import listo.client.ContextManager;
import listo.client.Convert;
import listo.client.model.ObjectId;
import listo.client.model.Task;
import listo.client.model.Tasks;
import listo.client.model.operations.AttachFolderOp;
import listo.client.model.operations.MoveBetweenFoldersOp;
import listo.client.model.operations.Operation;
import listo.client.model.operations.RepositionFolderOp;
import listo.client.viewlists.FolderView;
import listo.client.viewlists.FolderViewList;
import listo.utils.logging.Log;
import org.apache.commons.lang.ArrayUtils;

import javax.swing.*;
import java.awt.datatransfer.Transferable;

public class FolderViewListTransferHandler extends BaseTransferHandler {

    @Inject
    public FolderViewListTransferHandler(ContextManager contextManager, Log log) {
        super(contextManager, log);
    }

    //********************************************************************
    //*                             EXPORT
    //********************************************************************

    public int getSourceActions(JComponent c) {
        return MOVE;
    }

    protected Transferable createTransferable(JComponent c) {
        if (!(c instanceof FolderViewList)) return null;

        FolderViewList folderViewList = (FolderViewList) c;
        FolderView[] dragViews = Convert.toFolderViews(folderViewList.getSelectedValues());
        if (ArrayUtils.contains(dragViews, folderViewList.getViewRoot())) return null;

        return new FolderViewSelection(dragViews);
    }

    //********************************************************************
    //*                             IMPORT
    //********************************************************************

    @SuppressWarnings({"RedundantIfStatement"})
    public boolean canImport(TransferSupport support) {
        if (!support.isDrop()) return false;

        JList.DropLocation location = (JList.DropLocation) support.getDropLocation();
        int dropIx = location.getIndex();
        FolderViewList folderViewList = (FolderViewList) support.getComponent();
        FolderView dropView = (FolderView) folderViewList.getViewAt(dropIx);
        if (dropView == null) return false;

        if (support.isDataFlavorSupported(TaskSelection.TASK_FLAVOR)) {
            folderViewList.setDropMode(DropMode.ON);

            // we can only drop tasks on top of views, not in between
            if (location.isInsert()) return false;

            // we cannot drop on a folder that is already attached to one of the dragTasks
            Tasks dragTasks = (Tasks) getSelection(support, TaskSelection.TASK_FLAVOR);
            for (Task task : dragTasks) {
                if (task.hasFolders(dropView.getFolder().getId())) return false;
            }

            // if we are dragging tasks from the trash force a "move"
            if (dragTasks.allDeleted()) {
                support.setDropAction(MOVE);
            } else {
                // if we have one currently selected folder view, all is well
                // otherwise, if the dragTasks don't have exactly one common attached folder we force a "COPY"
                FolderView[] selectedViews = Convert.toFolderViews(folderViewList.getSelectedValues());
                if (selectedViews.length != 1 && dragTasks.getCommonFolders().size() != 1) support.setDropAction(COPY);
            }
            return true;
        }
        if (support.isDataFlavorSupported(FolderViewSelection.VIEW_FLAVOR)) {
            folderViewList.setDropMode(DropMode.ON_OR_INSERT);

            FolderView[] dragViews = (FolderView[]) getSelection(support, FolderViewSelection.VIEW_FLAVOR);

            // we cannot drop several folders
            if (dragViews.length > 1) return false;

            // we cannot drop onto our parent
            FolderView dragView = dragViews[0];
            if (!location.isInsert() && dropView == dragView.getParent()) return false;

            // we cannot drop right before our current position
            int dragIx = folderViewList.indexOf(dragView);
            if (location.isInsert() && dragIx == dropIx) return false;

            // we cannot drop right after our current position if this position would be on the same level
            if (location.isInsert() && dragIx == dropIx - 1 && dropView.getParent() == dragView.getParent()) {
                return false;
            }

            // we cannot drop on to ourselves or descendants of ourselves
            if (dragView.contains(dropView)) return false;

            return true;
        }

        return false;
    }

    protected Operation createDropOperation(TransferSupport support) {
        JList.DropLocation location = (JList.DropLocation) support.getDropLocation();
        int dropIx = location.getIndex();
        FolderViewList folderViewList = (FolderViewList) support.getComponent();
        FolderView dropView = (FolderView) folderViewList.getViewAt(dropIx);

        if (support.isDataFlavorSupported(TaskSelection.TASK_FLAVOR)) {
            Tasks dragTasks = (Tasks) getSelection(support, TaskSelection.TASK_FLAVOR);
            ObjectId folderId = dropView.getFolder().getId();

            if (support.getDropAction() == MOVE && !dragTasks.allDeleted()) {
                FolderView[] selectedViews = Convert.toFolderViews(folderViewList.getSelectedValues());

                MoveBetweenFoldersOp op = new MoveBetweenFoldersOp();
                op.setTasks(dragTasks);
                op.setFrom(selectedViews.length == 1 ? selectedViews[0].getFolder().getId() :
                        dragTasks.getCommonFolders().get(0));
                op.setTo(folderId);
                return op;
            }
            AttachFolderOp op = new AttachFolderOp();
            op.setTasks(dragTasks);
            op.setFolder(folderId);
            return op;
        }
        if (support.isDataFlavorSupported(FolderViewSelection.VIEW_FLAVOR)) {
            FolderView dragView = ((FolderView[]) getSelection(support, FolderViewSelection.VIEW_FLAVOR))[0];
            RepositionFolderOp op = new RepositionFolderOp();
            op.setFolder(dragView.getFolder().getId());
            if (location.isInsert()) {
                FolderView dropViewParent = dropView != null ? dropView.getParent() : folderViewList.getViewRoot();
                if (dropViewParent != folderViewList.getViewRoot()) op.setParent(dropViewParent.getFolder().getId());
                if (dropView != null) {
                    int pos = dropViewParent.getSubViews().indexOf(dropView);
                    if (dropViewParent == dragView.getParent() && pos > dropViewParent.getSubViews()
                            .indexOf(dragView)) {
                        pos--;
                    }
                    op.setPosition(pos);
                }
            } else {
                if (dropView != folderViewList.getViewRoot()) op.setParent(dropView.getFolder().getId());
            }
            return op;
        }
        return null;
    }

}